package cn.lmxdev.ptms.config;

import cn.lmxdev.ptms.handler.security.CustomAuthenticationFailureHandler;
import cn.lmxdev.ptms.handler.security.CustomAuthenticationSuccessHandler;
import cn.lmxdev.ptms.service.IUserServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfig {
    private final IUserServlet userServlet;
    private final CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
    private final CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Autowired
    public SecurityConfig(
            IUserServlet userServlet,
            CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler,
            CustomAuthenticationFailureHandler customAuthenticationFailureHandler
    ) {
        this.userServlet = userServlet;
        this.customAuthenticationSuccessHandler = customAuthenticationSuccessHandler;
        this.customAuthenticationFailureHandler = customAuthenticationFailureHandler;
    }

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http.headers().frameOptions().sameOrigin().and()  // 页面只能被本站页面嵌入到iframe或者frame中
                .csrf().disable()  // 关闭 CSRF
                .cors().disable()  // 关闭 CORS
                .userDetailsService(this.userServlet)  // 设置用户服务
                .formLogin(formLogin -> formLogin
                        .usernameParameter("account")  // 配置定义账号参数名
                        .passwordParameter("password")  // 配置自定义密码参数名
                        .loginPage("/static/login.html")  // 配置登录页面URL
                        .loginProcessingUrl("/api/user/login")  // 配置登录表单提交路径
                        .successHandler(this.customAuthenticationSuccessHandler)  // 处理登录成功处理器
                        .failureHandler(this.customAuthenticationFailureHandler))  // 配置登录失败处理器
                .logout(logout -> logout
                        .logoutUrl("/api/user/logout")  // 配置注销接口
                        .logoutSuccessUrl("/static/login.html"))  // 配置注销成功后跳转的URL
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers(
                                "/static/css/**",  // 放通样式资源
                                "/static/images/**",  // 放通图片资源
                                "/static/js/**",  // 放通脚本资源
                                "/static/svg/**",  // 放通图标资源
                                "/static/login.html",  // 放通登录页面
                                "/api/user/login",  // 放通登录接口
                                "/static/register.html",  // 放通注册页面
                                "/api/user/register",  // 放通注册接口
                                "/api/user/logout",  // 放通注销接口
                                "/api/department/list",  // 查询学院列表（注册页面需要）
                                "/api/specialty/list"  // 查询专业列表（注册页面需要）
                        ).permitAll()  // 放通URL
                        .anyRequest().authenticated())  // 其它资源认证通过后放通
                .build();  // 构建
    }

    /* 密码编码器 */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /* 获取AuthenticationManager（认证管理器） */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    /* 配置跨源访问(CORS) */
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }
}
